package STRAM(wrapSTRAM, mkWrapSTRAM) where
import FIFOF
import Connectable
import GetPut
import ClientServer
import RAM
import SyncSRAM
import SRAM
import TRAM

--@
--@ \index{STRAM@\te{STRAM} (package)|textbf}
--@ The \te{TSRAM} package corresponds to the \te{SRAM} package, but for tagged SRAMs.

--@ \index{mkWrapSTRAM@\te{mkWrapSTRAM} (function)|textbf}
--@ \begin{libverbatim}
--@ module mkWrapSTRAM#(Module#(SyncSRAMS#(lat, adrs, dtas)) mkRam)
--@                                             (TRAM#(tg, adr, dta))
--@   provisos (Bits#(adr, adrs),
--@             Bits#(dta, dtas),
--@             Bits#(tg, tgs),
--@             Add#(1, lat, lat1),
--@             Log#(lat1, llat));
--@ \end{libverbatim}
mkWrapSTRAM :: (IsModule m c, Bits adr adrs, Bits dta dtas, Bits tg tgs, Add 1 lat lat1, Log lat1 llat) =>
               m (SyncSRAMS lat adrs dtas) -> m (TRAM tg adr dta)
mkWrapSTRAM mkRam = do
    sram :: SyncSRAMS lat adrs dtas <- mkRam
    (cram, ram) :: (SyncSRAMC lat adrs dtas, TRAM tg adr dta) <- wrapSTRAM
    sram <-> cram
    return ram

--@ \index{wrapSTRAM@\te{wrapSTRAM} (module)|textbf}
--@ \begin{libverbatim}
--@ module wrapSTRAM(Tuple2 #(SyncSRAMC#(lat, adrs, dtas), TRAM#(tg, adr, dta)))
--@   provisos (Bits#(adr, adrs),
--@             Bits#(dta, dtas),
--@             Bits#(tg, tgs),
--@             Add#(1, lat, lat1),
--@             Log#(lat1, llat));
--@ \end{libverbatim}
wrapSTRAM :: (IsModule m c, Bits adr adrs, Bits dta dtas, Bits tg tgs, Add 1 lat lat1, Log lat1 llat) =>
             m (SyncSRAMC lat adrs dtas, TRAM tg adr dta)
wrapSTRAM =
  module
    fifo :: FIFOF tg <- mkSizedFIFOF (valueOf lat + 4)
    cs :: (SyncSRAMC lat adrs dtas, RAM adr dta) <- wrapSRAM
    let ram = cs.snd
    interface -- Pair
       (cs.fst,
        interface Server
            request =
             interface Put
               put (TRAM.Read (tag, address)) =
                action
                 fifo.enq tag
                 ram.request.put (RAM.Read address)
               put (TRAM.Write (address, value)) =
                       ram.request.put (RAM.Write (address, value))
            response =
             interface Get
              get = do
                d :: dta <- ram.response.get
                fifo.deq
                return (fifo.first,d)
       )
